package com.xiaochi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.xiaochi.subject.common.entity.PageResult;
import com.xiaochi.subject.common.enums.IsDeletedEnum;
import com.xiaochi.subject.common.enums.SubjectLikeStatusEnum;
import com.xiaochi.subject.common.util.LoginUtil;
import com.xiaochi.subject.domain.convert.SubjectInfoConverter;
import com.xiaochi.subject.domain.convert.SubjectLikedBOConverter;
import com.xiaochi.subject.domain.entity.SubjectInfoBO;
import com.xiaochi.subject.domain.entity.SubjectLikedBO;
import com.xiaochi.subject.domain.redis.RedisUtil;
import com.xiaochi.subject.domain.service.SubjectLikedDomainService;
import com.xiaochi.subject.infra.basic.entity.SubjectInfo;
import com.xiaochi.subject.infra.basic.entity.SubjectLiked;
import com.xiaochi.subject.infra.basic.service.SubjectInfoService;
import com.xiaochi.subject.infra.basic.service.SubjectLikedService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 题目点赞表 领域service实现了
 *
 * @author zqx
 * @since 2024-09-12 15:23:57
 */
@Service
@Slf4j
public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService {

    @Resource
    private SubjectLikedService subjectLikedService;

    @Resource
    private SubjectInfoService subjectInfoService;

    @Resource
    private RedisUtil redisUtil;

    private static final String SUBJECT_LIKE_KEY = "subject.liked";

    private static final String SUBJECT_LIKE_COUNT_KEY = "subject.liked.count";

    private static final String SUBJECT_LIKE_DETAIL_KEY = "subject.liked.detail";

    @Override
    public void add(SubjectLikedBO subjectLikedBO) {
        // todo 一共三个 题目和用户之间的点赞状态hash，所有的点赞状态都在这个hash里  这个题目的点赞数量  题目被谁点赞
        Long subjectId = subjectLikedBO.getSubjectId();
        String likeUserId = subjectLikedBO.getLikeUserId();
        Integer status = subjectLikedBO.getStatus();
        String hashKey = buildeSubjectLikedKey(subjectId.toString(), likeUserId);
        redisUtil.putHash(SUBJECT_LIKE_KEY,hashKey,status);
        String countKey = SUBJECT_LIKE_COUNT_KEY + "." + subjectId;
        String detailKey = SUBJECT_LIKE_DETAIL_KEY + "." + subjectId +"." + likeUserId;
        if (SubjectLikeStatusEnum.LIKE.getCode() == status) {
            //点赞
            redisUtil.increment(countKey,1);
            //给题目记上谁点的
            redisUtil.set(detailKey,"1");
        }else {
            Integer count = redisUtil.getInt(countKey);
            if (Objects.isNull(count) || count <= 0){
                return;
            }
            redisUtil.increment(countKey,-1);
            redisUtil.del(detailKey);
        }

    }

    @Override
    public Boolean isLiked(String subjectId, String userId) {
        String detailKey = SUBJECT_LIKE_DETAIL_KEY + "." + subjectId +"." + userId;
        return redisUtil.exist(detailKey);
    }

    @Override
    public Integer getLikedCount(String subjectId) {
        String countKey = SUBJECT_LIKE_COUNT_KEY + "." + subjectId;
        Integer count = redisUtil.getInt(countKey);
        if (Objects.isNull(count) || count <= 0){
            return 0;
        }
        //todo 这样可以保证多线程情况下，数据出错的情况减小
        // todo 多线程场景 分布式系统场景 设计模式影响（例如，在一些代理模式或装饰器模式的实现中，可能需要对数据的获取进行额外的处理或记录）
        // todo 还可以对代码增强维护性
        return redisUtil.getInt(countKey);
    }

    private String buildeSubjectLikedKey(String subjectId,String userId){
        return subjectId + ":" + userId;
    }

    @Override
    public Boolean update(SubjectLikedBO subjectLikedBO) {
        SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
        return subjectLikedService.update(subjectLiked) > 0;
    }

    @Override
    public Boolean delete(SubjectLikedBO subjectLikedBO) {
        SubjectLiked subjectLiked = new SubjectLiked();
        subjectLiked.setId(subjectLikedBO.getId());
        subjectLiked.setIsDeleted(IsDeletedEnum.DELETED_ENUM.getCode());
        return subjectLikedService.update(subjectLiked) > 0;
    }

    @Override
    public void syncLiked() {
        Map<Object,Object> subjectLikedMap = new HashMap<>();
        subjectLikedMap = redisUtil.getHashAndDelete(SUBJECT_LIKE_KEY);
        if (log.isInfoEnabled()){
            log.info("syncLiked.subjectLikedMap:{}", JSON.toJSONString(subjectLikedMap));
        }
        if (MapUtils.isEmpty(subjectLikedMap)){
            return;
        }
        //同步到数据库
        List<SubjectLiked> subjectLikedList = new LinkedList<>();
        subjectLikedMap.forEach((key,val) -> {
            SubjectLiked subjectLiked = new SubjectLiked();
            String[] keys = key.toString().split(":");
            String subjectId = keys[0];
            String likedUserId = keys[1];
            subjectLiked.setSubjectId(Long.valueOf(subjectId));
            subjectLiked.setLikeUserId(likedUserId);
            subjectLiked.setStatus(Integer.valueOf(val.toString()));
            subjectLikedList.add(subjectLiked);
        });
        subjectLikedService.insertBatch(subjectLikedList);
    }

    @Override
    public PageResult<SubjectLikedBO> getSubjectLikedPage(SubjectLikedBO subjectLikedBO) {
        PageResult<SubjectLikedBO> pageResult = new PageResult<>();
        pageResult.setPageNo(subjectLikedBO.getPageNo());
        pageResult.setPageSize(subjectLikedBO.getPageSize());
        int start = (subjectLikedBO.getPageNo() - 1) * subjectLikedBO.getPageSize();
        SubjectLiked subjectLiked = SubjectLikedBOConverter.INSTANCE.convertBOToEntity(subjectLikedBO);
        subjectLiked.setLikeUserId(LoginUtil.getLoginId());
        int count = subjectLikedService.countByCondition(subjectLiked);
        if (count == 0){
            return pageResult;
        }
        List<SubjectLiked> subjectLikedList = subjectLikedService.queryPage(subjectLiked, start,
                subjectLikedBO.getPageSize());
        List<SubjectLikedBO> subjectInfoBOList = SubjectLikedBOConverter.INSTANCE.InfoListToInfoBoList(subjectLikedList);

        //这里查出题目名称
        subjectInfoBOList.forEach(info -> {
            SubjectInfo subjectInfo = subjectInfoService.queryById(info.getSubjectId());
            info.setSubjectName(subjectInfo.getSubjectName());
        });
        pageResult.setRecords(subjectInfoBOList);
        pageResult.setTotal(count);
        return pageResult;
    }

}
